{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ビルダ\n",
    "\n",
    "* [Builderパターン](http://www.techscore.com/tech/DesignPattern/Builder.html/)\n",
    "    * 柔軟にオブジェクトを生成できるパターン\n",
    "    * 同じ作成過程で異なる表現形式の結果を得るためのパターン\n",
    "        * 水に素材(砂糖/塩)を入れて混ぜる\n",
    "            * 作成過程は同じ\n",
    "            * 素材が違う\n",
    "    * <font color=\"red\">「作成過程」と「素材」をそれぞれ用意することで要望に柔軟に応えられる</font>\n",
    "* 構成要素\n",
    "    * Director\n",
    "        * 作成過程を決定する\n",
    "        * Builderで提供されているインタフェースのみを使用して処理を行う\n",
    "        * ここでは最後に砂糖水を作るための作成過程cookのメソッドを持つDirectorクラス\n",
    "    * Builder\n",
    "        * 表現形式\n",
    "        * 作業インタフェースを持つ\n",
    "        * 各メソッドのインタフェースを定める\n",
    "        * ここではSugarWaterBuilder\n",
    "            * 砂糖水を作るためのインタフェース\n",
    "            * 砂糖を入れる(add_sugar), 水を入れる(add_water), 砂糖水の状態を返す(result)メソッドがある\n",
    "    * ConcreteBuilder (具体ビルダ)\n",
    "        * Builderが定めたインタフェースの実装\n",
    "        * ここでは砂糖水クラスSugarWater\n",
    "* 使われる場面\n",
    "    * オブジェクトの生成に大量のコードが必要\n",
    "    * オブジェクトを作り出すのが難しい\n",
    "    * オブジェクト生成時に必要なチェックを行いたい\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":initialize"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# SugarWater： 砂糖水クラス (ConcreteBuilder：ビルダーの実装部分)\n",
    "class SugarWater\n",
    "  attr_accessor :water, :sugar\n",
    "  def initialize(water, sugar)\n",
    "    @water = water\n",
    "    @sugar = sugar\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":result"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# SugarWaterBuilder: 砂糖水を生成するためのインターフェイス (Builder)\n",
    "class SugarWaterBuilder\n",
    "  def initialize\n",
    "    @sugar_water = SugarWater.new(0,0)\n",
    "  end\n",
    "  \n",
    "  # 砂糖を加える\n",
    "  def add_sugar(sugar_amount)\n",
    "    @sugar_water.sugar += sugar_amount\n",
    "  end\n",
    "  \n",
    "  # 水を加える\n",
    "  def add_water(water_amount)\n",
    "    water_amount\n",
    "    @sugar_water.water += water_amount\n",
    "  end\n",
    "  \n",
    "  # 砂糖水の状態を返す\n",
    "  def result\n",
    "    @sugar_water\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":cook"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Director： 砂糖水の作成過程を取り決める\n",
    "class Director\n",
    "  def initialize(builder)\n",
    "    @builder = builder\n",
    "  end\n",
    "  \n",
    "  # 砂糖水の作成過程を定義する\n",
    "  def cook\n",
    "     @builder.add_water(150)\n",
    "     @builder.add_sugar(90)\n",
    "     @builder.add_water(300)\n",
    "     @builder.add_sugar(35)\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<SugarWaterBuilder:0x007f37844e4680 @sugar_water=#<SugarWater:0x007f37844e4630 @water=0, @sugar=0>>\n",
      "#<Director:0x007f37844e0a80 @builder=#<SugarWaterBuilder:0x007f37844e4680 @sugar_water=#<SugarWater:0x007f37844e4630 @water=0, @sugar=0>>>\n",
      "#<SugarWater:0x007f37844e4630 @water=450, @sugar=125>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "#<SugarWater:0x007f37844e4630 @water=450, @sugar=125>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p builder = SugarWaterBuilder.new\n",
    "p director = Director.new(builder)\n",
    "director.cook\n",
    "\n",
    "p builder.result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 塩水と砂糖水を作成できるようにする"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":add_material"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# SaltWater 塩水クラス (ConcreteBuilder：ビルダーの実装部分)\n",
    "class SaltWater\n",
    "  attr_accessor :water, :salt\n",
    "  def initialize(water, salt)\n",
    "    @water = water\n",
    "    @salt = salt\n",
    "  end\n",
    "  \n",
    "  # 素材(塩)を加える\n",
    "  def add_material(salt_amount)\n",
    "    @salt += salt_amount\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":add_material"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# SugarWater： 砂糖水クラス (ConcreteBuilder：ビルダーの実装部分)\n",
    "class SugarWater\n",
    "  attr_accessor :water, :sugar\n",
    "  def initialize(water, sugar)\n",
    "    @water = water\n",
    "    @sugar = sugar\n",
    "  end\n",
    "  \n",
    "  # 素材(砂糖)を加える\n",
    "  def add_material(sugar_amount)\n",
    "    @sugar += sugar_amount\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":result"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# SugarWaterBuilder： 加工した水を生成するためのインターフェイス(Builder)\n",
    "class WaterWithMaterialBuilder\n",
    "  def initialize(class_name)\n",
    "    @water_with_material = class_name.new(0,0)\n",
    "  end\n",
    "  \n",
    "  # 素材を入れる\n",
    "  def add_material(material_amount)\n",
    "    @water_with_material.add_material(material_amount)\n",
    "  end\n",
    "  \n",
    "  # 水を加える\n",
    "  def add_water(water_amount)\n",
    "    @water_with_material.water += water_amount\n",
    "  end\n",
    "  \n",
    "  # 加工水の状態を返す\n",
    "  def result\n",
    "    @water_with_material\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ":cook"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Director： 加工水の作成過程を取り決める\n",
    "class Director\n",
    "  def initialize(builder)\n",
    "    @builder = builder\n",
    "  end\n",
    "  \n",
    "  def cook\n",
    "    @builder.add_water(150)\n",
    "    @builder.add_material(90)\n",
    "    @builder.add_water(300)\n",
    "    @builder.add_material(35)\n",
    "  end\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<SugarWater:0x007f37850a2d78 @water=450, @sugar=125>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "#<SugarWater:0x007f37850a2d78 @water=450, @sugar=125>"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "builder = WaterWithMaterialBuilder.new(SugarWater)\n",
    "director = Director.new(builder)\n",
    "director.cook\n",
    "\n",
    "p builder.result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<SaltWater:0x007f3785048aa8 @water=450, @salt=125>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "#<SaltWater:0x007f3785048aa8 @water=450, @salt=125>"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "builder = WaterWithMaterialBuilder.new(SaltWater)\n",
    "director = Director.new(builder)\n",
    "director.cook\n",
    "\n",
    "p builder.result"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.3.3",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.3.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
